package wdcod

import (
	"crypto"
	"crypto/md5"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/x509"
	"encoding/hex"
	"encoding/pem"
	"hash"
	"io"
	"os"
	//"path/filepath"
)

//Sha1Stream ...
type Sha1Stream struct {
	_sha1 hash.Hash
}

//Update ..
func (s *Sha1Stream) Update(data []byte) {
	if s._sha1 == nil {
		s._sha1 = sha1.New()
	}
	s._sha1.Write(data)
}

//Sum ..
func (s *Sha1Stream) Sum() string {
	return hex.EncodeToString(s._sha1.Sum([]byte("")))
}

//Sha1 ..计算一段内容的sha1值40位
func Sha1(data []byte) string {
	_sha1 := sha1.New()
	_sha1.Write(data)
	return hex.EncodeToString(_sha1.Sum([]byte("")))
}

//FileSha1 ..计算一个文件的sha1值40位
	func FileSha1(file *os.File) string {
	_sha1 := sha1.New()
	io.Copy(_sha1, file)
	return hex.EncodeToString(_sha1.Sum(nil))
}

//MD5  ..计算一段内容的MD5值32位
func MD5(data []byte) string {
	_md5 := md5.New()
	_md5.Write(data)
	return hex.EncodeToString(_md5.Sum([]byte("")))
}

//FileMD5 ..计算一个文件的md5值32位
func FileMD5(file *os.File) string {
	_md5 := md5.New()
	io.Copy(_md5, file)
	return hex.EncodeToString(_md5.Sum(nil))
}

//Getkeys ..s生成私钥和公钥
//例：Getkeys("/home/go/src/test")
//生成后公钥路径：/home/go/src/test/PublicKey.pem
//生成后私钥路径：/home/go/src/test/Private.pem
func Getkeys(keypath string) {
	//得到私钥
	privateKey, _ := rsa.GenerateKey(rand.Reader, 2048)
	//通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
	x509_Privatekey := x509.MarshalPKCS1PrivateKey(privateKey)
	//创建一个用来保存私钥的以.pem结尾的文件
	fp, _ := os.Create(keypath + "/Private.pem")
	defer fp.Close()
	//将私钥字符串设置到pem格式块中
	pem_block := pem.Block{
		Type:  "PUBLIC KEY",
		Bytes: x509_Privatekey,
	}
	//转码为pem并输出到文件中
	pem.Encode(fp, &pem_block)

	//处理公钥,公钥包含在私钥中
	publickKey := privateKey.PublicKey
	//接下来的处理方法同私钥
	//通过x509标准将得到的ras私钥序列化为ASN.1 的 DER编码字符串
	x509_PublicKey, _ := x509.MarshalPKIXPublicKey(&publickKey)
	pem_PublickKey := pem.Block{
		Type:  "PRIVATE KEY",
		Bytes: x509_PublicKey,
	}
	file, _ := os.Create(keypath + "/PublicKey.pem")
	defer file.Close()
	//转码为pem并输出到文件中
	pem.Encode(file, &pem_PublickKey)
}

//RSA_encrypter ..使用读取后的公钥buf进行对msg进行加密
func RSA_encrypter(buf []byte, msg []byte) []byte {
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码,得到一个interface类型的pub
	pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
	//加密操作,需要将接口类型的pub进行类型断言得到公钥类型
	cipherText, _ := rsa.EncryptPKCS1v15(rand.Reader, pub.(*rsa.PublicKey), msg)
	return cipherText
}

//RSA_encrypter_path 使用公钥文件进行加密
func RSA_encrypter_path(path string, msg []byte) []byte {
	//首先从文件中提取公钥
	fp, _ := os.Open(path)
	defer fp.Close()
	//测量文件长度以便于保存
	fileinfo, _ := fp.Stat()
	buf := make([]byte, fileinfo.Size())
	fp.Read(buf)
	//下面的操作是与创建秘钥保存时相反的
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码,得到一个interface类型的pub
	pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
	//加密操作,需要将接口类型的pub进行类型断言得到公钥类型
	cipherText, _ := rsa.EncryptPKCS1v15(rand.Reader, pub.(*rsa.PublicKey), msg)
	return cipherText
}

//RSA_decrypter ..使用读取后的私钥进行解密
func RSA_decrypter(buf []byte, cipherText []byte) []byte {
	block, _ := pem.Decode(buf)
	PrivateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
	//二次解码完毕，调用解密函数
	afterDecrypter, _ := rsa.DecryptPKCS1v15(rand.Reader, PrivateKey, cipherText)
	return afterDecrypter
}

//RSA_decrypter_path ..使用私钥文件进行解密
func RSA_decrypter_path(path string, cipherText []byte) []byte {
	//同加密时，先将私钥从文件中取出，进行二次解码
	fp, _ := os.Open(path)
	defer fp.Close()
	fileinfo, _ := fp.Stat()
	buf := make([]byte, fileinfo.Size())
	fp.Read(buf)
	block, _ := pem.Decode(buf)
	PrivateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
	//二次解码完毕，调用解密函数
	afterDecrypter, _ := rsa.DecryptPKCS1v15(rand.Reader, PrivateKey, cipherText)
	return afterDecrypter
}

//Signname 使用读取后的私钥签名，path是私钥路径，msg是要签名的信息
func Signname(buf []byte, msg []byte) []byte {
	//签名函数中需要的数据散列值
	block, _ := pem.Decode(buf)
	PrivateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
	//加密操作,需要将接口类型的pub进行类型断言得到公钥类型

	hash := sha256.Sum256(msg)
	//调用签名函数,填入所需四个参数，得到签名
	sign, _ := rsa.SignPKCS1v15(rand.Reader, PrivateKey, crypto.SHA256, hash[:])
	return sign
}

//Signname_path 使用私钥文件签名，path是私钥路径，msg是要签名的信息
func Signname_path(path string, msg []byte) []byte {
	//签名函数中需要的数据散列值
	//首先从文件中提取公钥
	fp, _ := os.Open(path)
	defer fp.Close()
	fileinfo, _ := fp.Stat()
	buf := make([]byte, fileinfo.Size())
	fp.Read(buf)
	block, _ := pem.Decode(buf)
	PrivateKey, _ := x509.ParsePKCS1PrivateKey(block.Bytes)
	//加密操作,需要将接口类型的pub进行类型断言得到公钥类型

	hash := sha256.Sum256(msg)
	//调用签名函数,填入所需四个参数，得到签名
	sign, _ := rsa.SignPKCS1v15(rand.Reader, PrivateKey, crypto.SHA256, hash[:])
	return sign
}

//VerifySign ..使用读取后的公钥进行签名数据验证
func VerifySign(buf []byte, signText []byte, plainText []byte) bool {
	//下面的操作是与创建秘钥保存时相反的
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码,得到一个interface类型的pub
	pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
	//签名函数中需要的数据散列值
	hash := sha256.Sum256(plainText)
	//验证签名
	err := rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hash[:], signText)
	if err != nil {
		return false
	} else {
		return true
	}
}

//VerifySign_path ..使用公钥文件进行签名数据验证
func VerifySign_path(path string, signText []byte, plainText []byte) bool {
	//首先从文件中提取公钥
	fp, _ := os.Open(path)
	defer fp.Close()
	//测量文件长度以便于保存
	fileinfo, _ := fp.Stat()
	buf := make([]byte, fileinfo.Size())
	fp.Read(buf)
	//下面的操作是与创建秘钥保存时相反的
	//pem解码
	block, _ := pem.Decode(buf)
	//x509解码,得到一个interface类型的pub
	pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
	//签名函数中需要的数据散列值
	hash := sha256.Sum256(plainText)
	//验证签名
	err := rsa.VerifyPKCS1v15(pub.(*rsa.PublicKey), crypto.SHA256, hash[:], signText)
	if err != nil {
		return false
	} else {
		return true
	}
}

